#pragma once

/*************************	Header *****************************/

#include "hamiltonian.h"
#include "lanczosmethod.h"

using arma::cx_vec;
using arma::cx_mat;

/*********************** Declaration ***************************/

// The Haydock Method Functor.
//
//	This function object is used to calculate the Green's function
//	of a state using a truncation approximation of the Lanczos tri-
//	diagonal matrix initated from that state. 
//	This functor include to date the calculation of the following:
//
//	-	The Green's function elements Gx(hw) of a state X for a 
//		given Unit.
//	-	The avg. full Green's function G(hw) for a given Unit.
//
// Options:
//	The options are public variables (accessable from outside the
//	class) and are set to default value at class construction time.
//
// (System*) system;		Default:	&System::Std
//		A pointer to the used system. The system contains variables 
//		needed to construct elements (coupling strengths etc.).
//		The system defaults to a statically generated system (the
//		standard system).
//
// (double) bias;			Default:	0
//		A double containing the current bias (for bi-layered 
//		systems).
//		The bias defaults to 0 i.e no bias.
//
// (vec) k;			Default:	vec(0,0,0)
//		A double vector containing the current k-point.
//		The k defaults to vec(0,0,0) i.e the gamma point.
//
// (vec) E;			Default:	vec(0)
//		A  double vector containing the energy sample points used in
//		the calculations. The size of this has little influence on 
//		the operation time.
//		The E defaults to vec(0) i.e only one sample point.
//
// (double) eta;			Default:	0.001
//		A double containing the broadening factor.
//		The eta defaults to 0.001.
//
// (size_t) N_states;	Default:	1000
//		An integer containing the number of lanczos states to use in the
//		calculations of the tri-diagonal matrix H_tilde.
//		The N_states defaults to 1000.
//
// (size_t) N_rand;	Default:	1
//		An integer containing the number of lanczos states to use in the
//		calculations of the tri-diagonal matrix H_tilde.
//		The N_rand defaults to 1.
//
// (func) updateProgress;	Default:	null
//		A function object containing an updating function to report
//		 the progress of calculations.
//		The updateProgress defaults to null i.e no function.
//
// Usage:
//	This function includes the following public operating functions.
//
//	(HaydockMethod &) operator()(int id, cx_vec X)
//		This operator (use by simply appending () to a HaydockMethod
//		type variable) calculates the Green's function element for the
//		state X. The operator returns the object it self for easy access
//		to result. The result is stored in the G result variable. The 
//		variable may be retrieved immidiately after calculation i.e:
//		hm(id,X).G // Calculate and retreive result.
//
//	(HaydockMethod &) operator()(int id)
//		This operator (use by simply appending () to a HaydockMethod
//		type variable) calculates the avg.  Green's function element. 
//		The operator returns the object it self for easy access	to 
//		result. The result is stored in the G result variable. The 
//		variable may be retrieved immidiately after calculation i.e:
//		hm(id).G // Calculate and retreive result.
// 
// Example:
//	Set options and get Green's function:
//
//		HaydockMethod hm; // Generate a hamilton object
//
//		hm.bias = current_bias; // Set the current bias
//		hm.E = current_energies; // Set the current energies
//
//		return hm(id).G; // Calculate and return result.
class GRAPHENETOOLS_DLL_API HaydockMethod
{
// Options:
public:
	// A pointer to the used system. The system contains variables 
	// needed to construct elements (coupling strengths etc.).
	System* system;
	// A double containing the current bias (for bi-layered 
	// systems).
	double bias;
	// A double vector containing the current k-point.
	vec k;
	// A  double vector containing the energy sample points used in
	// the calculations. The size of this has little influence on 
	// the operation time.
	vec E;
	// A double containing the broadening factor.
	double eta;
	// An integer containing the number of lanczos states to use in the
	// calculations of the tri-diagonal matrix H_tilde.
	size_t N_states;
	// An integer containing the number of lanczos states to use in the
	// calculations of the tri-diagonal matrix H_tilde.
	size_t N_rand;
	// A function object containing an updating function to report
	// the progress of calculations.
	std::function< void (const double &)> updateProgress;
	
// Usage:
	// This operator (use by simply appending () to a HaydockMethod
	// type variable) calculates the Green's function element for the
	// state X. The operator returns the object it self for easy access
	// to result. The result is stored in the G result variable. The 
	// variable may be retrieved immidiately after calculation i.e:
	// hm(id,X).G // Calculate and retreive result.
	HaydockMethod & operator()(int id, cx_vec X);

	// This operator (use by simply appending () to a HaydockMethod
	// type variable) calculates the avg.  Green's function element. 
	// The operator returns the object it self for easy access	to 
	// result. The result is stored in the G result variable. The 
	// variable may be retrieved immidiately after calculation i.e:
	// hm(id).G // Calculate and retreive result.
	HaydockMethod & operator()(int id);

	
// Results:

	// The Green's function element for a Unit. Use 
	// operator()(int id) to set.
	cx_vec G;
	
// Constructor
	HaydockMethod();

protected:
	// This variable contains the update step
	double step;
	// This function attempts to update the progress.
	void try_updateProgress() const;

	// This function returns the Hamilton matrix H.
	sp_cx_mat getHamiltonMatrix(int id) const;
	// This function returns a random phase state, i.e |r> = 1/R sum_1^R exp(i phi) |i>.
	static cx_vec randomPhaseState(size_t n);
	// This function returns the Greens matrix G.
	static complex calcGreens(const vec &alpha, const vec &beta, const complex &z);
};

